package com.xiaoyu.lanling.feature.chat.presenter

import `in`.srain.cube.app.lifecycle.IComponentContainer
import `in`.srain.cube.concurrent.AppThreads
import `in`.srain.cube.concurrent.SimpleTask
import `in`.srain.cube.util.StringUtil
import `in`.srain.cube.util.internal.AppSupplier
import android.annotation.SuppressLint
import android.content.Intent
import android.text.TextUtils
import com.xiaoyu.base.data.UserInfoDataProvider
import com.xiaoyu.base.entity.ConversationEntity
import com.xiaoyu.base.event.AppEventBus
import com.xiaoyu.base.event.SimpleEventHandler
import com.xiaoyu.base.model.User
import com.xiaoyu.base.utils.RxUtils
import com.xiaoyu.im.datamodel.ConversationType
import com.xiaoyu.im.provider.ConversationManager
import com.xiaoyu.lanling.common.Constant
import com.xiaoyu.lanling.event.audio.AudioResultEvent
import com.xiaoyu.lanling.event.camera.ImageCaptureEvent
import com.xiaoyu.lanling.event.camera.TinyVideoCaptureEvent
import com.xiaoyu.lanling.event.chat.ChatMessageCallItemRecallClickEvent
import com.xiaoyu.lanling.event.chat.ChatReceiveAudioPlayComplementEvent
import com.xiaoyu.lanling.event.chat.MessageListUpdateEvent
import com.xiaoyu.lanling.event.chat.emoji.ChatEmojiCheckEvent
import com.xiaoyu.lanling.event.chat.relationship.RelationshipEvent
import com.xiaoyu.lanling.event.chat.tease.QuickStatementsEvent
import com.xiaoyu.lanling.event.chat.tease.TeaseClickEvent
import com.xiaoyu.lanling.event.gift.GetNotPlayedGiftAnimationEvent
import com.xiaoyu.lanling.event.gift.GiveGiftAndSendMessageEvent
import com.xiaoyu.lanling.event.gift.ReceiveGiftEvent
import com.xiaoyu.lanling.event.media.mediaselector.MediaSelectorResultEvent
import com.xiaoyu.lanling.feature.chat.contract.ChatContract
import com.xiaoyu.lanling.feature.chat.data.MessageListData
import com.xiaoyu.lanling.feature.chat.data.relationship.RelationshipData
import com.xiaoyu.lanling.feature.chat.data.teast.TeaseData
import com.xiaoyu.lanling.feature.chat.model.intent.ChatIntentModel
import com.xiaoyu.lanling.feature.chat.model.relationship.Intimacy.Companion.MIN_TOTAL_NUM
import com.xiaoyu.lanling.feature.chat.model.videomodel.ChatVideoModel
import com.xiaoyu.lanling.feature.gift.data.GiftData
import com.xiaoyu.lanling.feature.im.provider.MessageDataProvider
import com.xiaoyu.lanling.feature.im.request.MessageRequestBuilder
import com.xiaoyu.lanling.media.selector.MediaSelectorFromType
import com.xiaoyu.lanling.util.ImageFileCompressUtils
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

class ChatPresenter(val view: ChatContract.View) : ChatContract.Presenter {

    private val requestTag = Any()

    private var mChatIntentModel: ChatIntentModel? = null
    private val teaseData by lazy { TeaseData() }

    override fun getRequestTag(): Any {
        return requestTag
    }

    override fun processIntent(intent: Intent) {
        val uid: String = intent.getStringExtra(Constant.PARAM_UID) ?: ""
        val chatId: String = intent.getStringExtra(Constant.PARAM_CHAT_ID) ?: ""
        val messageId: String = intent.getStringExtra(Constant.PARAM_MESSAGE_ID) ?: ""
        val from: String = intent.getStringExtra(Constant.PARAM_FROM) ?: ""

        if (!TextUtils.isEmpty(chatId)) {
            createChatConversationForCid(chatId, messageId, from)
        } else if (!TextUtils.isEmpty(uid)) {
            createChatConversationForUid(uid, messageId, from)
        } else {
            view.finish()
        }
    }

    override fun setChatModel(chatIntentModel: ChatIntentModel) {
        mChatIntentModel = chatIntentModel
        view.setChatModel(chatIntentModel)
    }

    override fun initEvent(container: IComponentContainer) {
        AppEventBus.bindContainerAndHandler(container, object : SimpleEventHandler() {
            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: MessageListUpdateEvent) {
                if (event.isNotFromThisRequestTag(mChatIntentModel?.mChatToken)) {
                    return
                }
                view.updateMessageList(event.list, event.newLoad, event.isFromSearch, event.messageIndex, event.messageId)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: ChatEmojiCheckEvent) {
                view.checkEmoji(event.chatEmojiGridItem.emojiKey)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: TeaseClickEvent) {
                sendMessageText(event.title)
                teaseData.increaseFrequency(event.id)
                view.hideMediaLayout()
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: QuickStatementsEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                view.showTeaseList(event.list)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: MediaSelectorResultEvent) {
                if (event.fromType != MediaSelectorFromType.CHAT || event.mediaPathList.isEmpty()) {
                    return
                }
                for (item in event.result.mediaList) {
                    item.path?.let {
                        if (item.isImage) {
                            val imageList = listOf(it)
                            sendMessageImage(imageList)
                        } else if (item.isVideo) {
                            val videoModel = ChatVideoModel.videoToModel(item.path, item.duration)
                                    ?: return
                            sendMessageVideo(videoModel)
                        }
                    }
                }
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: TinyVideoCaptureEvent) {
                val videoModel = ChatVideoModel.videoToModel(event.path, event.duration.toLong())
                sendMessageVideo(videoModel)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: ImageCaptureEvent) {
                sendMessageImage(listOf(event.imagePath))
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: AudioResultEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                val duration = event.getDurationInSecond()
                sendMessageAudio(event.filePath, duration)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: ChatReceiveAudioPlayComplementEvent) {
                if (!ConversationManager.getInstance().isCurrentOpenConversation(event.message.chatToken)) {
                    return
                }
                MessageDataProvider.instance.onReceiveAudioMessagePlayCompleteAsync(event.message)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: RelationshipEvent) {
                if (event.toUid != mChatIntentModel?.mChatToken?.uid) {
                    return
                }
                if (event.intimacy.totalNum >= MIN_TOTAL_NUM) {
                    view.updateIntimacy(event.intimacy)
                } else {
                    view.updateTitle(mChatIntentModel?.mChatTitle)
                }
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: GiveGiftAndSendMessageEvent) {
                if (event.from != Constant.From.USER && event.from != Constant.From.CHAT) {
                    return
                }
                view.enqueueOrPlayGiftAnimation(event.gift)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: ReceiveGiftEvent) {
                if (event.senderUid != mChatIntentModel?.mUser?.uid) {
                    return
                }
                view.enqueueOrPlayGiftAnimation(event.gift)
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: GetNotPlayedGiftAnimationEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                for (gift in event.gifts) {
                    view.enqueueOrPlayGiftAnimation(gift)
                }
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: ChatMessageCallItemRecallClickEvent) {
                view.performClickCall()
            }
        })
    }

    override val isSingleChat: Boolean
        get() = mChatIntentModel?.isSingleChat == true

    override val isSingleNormalChat: Boolean
        get() = mChatIntentModel?.isSingleNormalChat == true

    override val chatType: String
        get() = mChatIntentModel?.mConversationType ?: ConversationType.SINGLE;

    override fun loadMoreMessageList() {
        val chatId = mChatIntentModel?.mChatToken?.chatId ?: return
        if (!TextUtils.isEmpty(chatId)) {
            MessageListData.instance.loadNextMessageList(chatId)
        }
    }

    override fun sendMessageText(message: String) {
        mChatIntentModel?.let { chatIntentModel ->
            MessageRequestBuilder.newBuilder(chatIntentModel.mChatToken, chatIntentModel.mFromType)
                    .text(message)
                    .buildAndSend()
        }
    }

    override fun onStartChat() {
        val chatId: String = mChatIntentModel?.mChatToken?.chatId ?: return
        val messageId: String = mChatIntentModel?.messageIDThenReset ?: return

        if (!StringUtil.isAnyEmpty(chatId, messageId)) {
            MessageListData.instance.loadFirstMessageListByMessageId(chatId, messageId)
        } else if (!TextUtils.isEmpty(chatId)) {
            MessageListData.instance.loadFirstMessageList(chatId)
        } else {
            MessageListUpdateEvent(mChatIntentModel?.mChatToken, listOf(), newLoad = true, isFromSearch = false, messageIndex = -1).post()
        }

        if (isSingleNormalChat) {
            mChatIntentModel?.mChatToken?.uid?.let {
                RelationshipData.getRelationship(requestTag, it)
                GiftData.getNotPlayedGiftAnimation(requestTag, it)
            }
        } else {
            view.updateTitle(mChatIntentModel?.mChatTitle)
        }
        updateConversationViewVisible(true)
    }

    public fun updateConversationViewVisible(visible: Boolean) {
        ConversationManager.getInstance().updateViewVisible(visible)
    }

    override fun onStopChat() {
        mChatIntentModel?.let {
            ConversationManager.getInstance().onConversationClose(it.mChatToken)
        }
    }

    override fun loadTeaseList() {
        teaseData.quickStatements(requestTag)
    }

    private fun createChatConversationForUid(uid: String, messageId: String, fromType: String) {
        createChatConversationForFunction(
                AppSupplier { fetchUserToCreateChatConversation(uid, messageId, fromType) },
                Runnable { UserInfoDataProvider.getInstance().ensureUser(uid) })
    }

    private fun createChatConversationForCid(chatId: String, messageId: String, fromType: String) {
        createChatConversationForFunction(
                AppSupplier { fetchConversationToCreateChatConversation(chatId, messageId, fromType) },
                Runnable { ConversationManager.getInstance().ensureConversation(chatId) })
    }

    private fun fetchUserToCreateChatConversation(uid: String, messageId: String, fromType: String): Boolean {
        val user: User = UserInfoDataProvider.getInstance().fetchFromMemory(uid)
        if (user.isNobody) {
            return false
        }
        createChatConversation(ChatIntentModel.fromUser(user), messageId, fromType)
        return true
    }

    private fun fetchConversationToCreateChatConversation(chatId: String, messageId: String, fromType: String): Boolean {
        val model: ConversationEntity = ConversationManager.getInstance().fetchConversation(chatId)
                ?: return false
        createChatConversation(ChatIntentModel.fromConversationModel(model), messageId, fromType)
        return true
    }

    private fun createChatConversation(chatIntentModel: ChatIntentModel, messageId: String, fromType: String) {
        chatIntentModel.setMessageId(messageId)
        chatIntentModel.setFromType(fromType)
        setChatModel(chatIntentModel)
    }

    private fun createChatConversationForFunction(createFunction: AppSupplier<Boolean>, ensureFunction: Runnable) {
        if (createFunction.get()) {
            return
        }
        view.showProgressDialog()
        AppThreads.runOnIOThread(object : SimpleTask() {

            override fun doInBackground() {
                ensureFunction.run()
            }

            override fun onFinish(canceled: Boolean) {
                view.dismissProgressDialog()
                if (!createFunction.get()) {
                    view.finish()
                }
            }
        })
    }

    @SuppressLint("CheckResult")
    fun sendMessageImage(imageFilePathList: List<String>) {
        ImageFileCompressUtils.compressBatchAsFile(imageFilePathList.toTypedArray())
                .filter { paths -> paths.isNotEmpty() }
                .compose(RxUtils.ioToMainMaybeScheduler())
                .subscribe({ paths ->
                    mChatIntentModel?.let {
                        MessageRequestBuilder.newBuilder(it.mChatToken, it.mFromType)
                                .imageList(paths.toList())
                                .buildAndSend()
                    }
                }, { t -> t.printStackTrace() })
    }

    private fun sendMessageAudio(filePath: String, duration: Int) {
        mChatIntentModel?.let {
            MessageRequestBuilder.newBuilder(it.mChatToken, it.mFromType)
                    .audio(filePath, duration)
                    .buildAndSend()
        }
    }

    fun sendMessageVideo(videoModel: ChatVideoModel) {
        mChatIntentModel?.let {
            MessageRequestBuilder.newBuilder(it.mChatToken, it.mFromType)
                    .video(videoModel)
                    .buildAndSend()
        }
    }
}